home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 319_01 / dir.c < prev    next >
C/C++ Source or Header  |  1990-06-16  |  21KB  |  1,023 lines

  1. /*
  2.     CPP V5 -- directives
  3.  
  4.     source:  dir.c
  5.     started: October 7, 1985
  6.     version: May 31, 1988
  7.  
  8.     External routines defined in this file: do_pp
  9.  
  10.     Written by Edward K. Ream.
  11.     This software is in the public domain.
  12.  
  13.     See the read.me file for disclaimer and other information.
  14. */
  15.  
  16. #include "cpp.h"
  17.  
  18. #define TRACE_LINE(name) TRACEP(name, printf("line %d\n", t_line))
  19.  
  20. static long    eval        (void);
  21. static long     eval1        (void);
  22. static bool    gt_prec        (en_tokens, en_tokens);
  23. static bool    isfnch        (int, en_tokens);
  24.  
  25. static void    pp_elif        (void);
  26. static void    pp_else        (void);
  27. static void    pp_endif    (void);
  28. static void    pp_enum        (void);
  29. static void    pp_error    (void);
  30. static void    pp_if        (void);
  31. static void    pp_ifdef    (bool);
  32. static void    pp_incl        (void);
  33. static void    pp_line        (void);
  34. static void    pp_undef    (void);
  35. static int    prec        (int);
  36.  
  37. static void    push_op        (en_tokens);
  38. static en_tokens pop_op        (void);
  39. static void    push_val    (long);
  40. static long    pop_val        (void);
  41. static void    skip_lines    (void);
  42.  
  43. /*
  44.     Do one preprocessor directive.
  45. */
  46.  
  47. #define EQL(string) str_eq(t_symbol+1,string+1)
  48.  
  49. void
  50. do_pp()
  51. {
  52.     TICK("do_pp");
  53.  
  54.     skip_ws(FALSE);
  55.  
  56.     /* Get the directive into t_symbol[]. */
  57.     if (!isalpha(ch)) {
  58.         goto not_alpha;
  59.     }
  60.     t_id(t_symbol, MAX_SYMBOL);
  61.  
  62.     /* 3/3/89: bug fix:  full white space allowed here. */
  63.     skip_ws(FALSE);
  64.  
  65.     /* Skip simple white space after the directive. */
  66.     /* -----
  67.     while (ch == ' ' || ch == '\t') {
  68.         sysnext();
  69.     }
  70.     ----- */
  71.  
  72.     switch(t_symbol [0]) {
  73.  
  74.     case 'd':
  75.         if (t_length == 6 && EQL("define")) {
  76.             pp_def();
  77.             return;
  78.         }
  79.         goto not_pp;
  80.  
  81.     case 'e':
  82.         if (t_length == 4) {
  83.             if (EQL("else")) {
  84.                 pp_else();
  85.                 return;
  86.             }
  87.             else if (EQL("elif")) {
  88.                 pp_elif();
  89.                 return;
  90.             }
  91.         }
  92. #ifdef HAS_PP_ENUM
  93.         else if (t_length == 4 && EQL("enum")) {
  94.             pp_enum();
  95.             return;
  96.         }
  97. #endif
  98.         else if (t_length == 5 && EQL("endif")) {
  99.             pp_endif();
  100.             return;
  101.         }
  102.         else if (t_length == 5 && EQL("error")) {
  103.             pp_error();
  104.             return;
  105.         }
  106.         goto not_pp;
  107.  
  108.     case 'i':
  109.         switch(t_length) {
  110.         case 2:    if (EQL("if")) {
  111.                 pp_if();
  112.                 return;
  113.             }
  114.             goto not_pp;
  115.         case 5:    if (EQL("ifdef")) {
  116.                 pp_ifdef(TRUE);
  117.                 return;
  118.             }
  119.             goto not_pp;
  120.         case 6:    if (EQL("ifndef")) {
  121.                 pp_ifdef(FALSE);
  122.                 return;
  123.             }
  124.             goto not_pp;
  125.         case 7:    if (EQL("include")) {
  126.                 pp_incl();
  127.                 return;
  128.             }
  129.             goto not_pp;
  130.         }
  131.         goto not_pp;
  132.  
  133.     case 'l':
  134.         if (t_length == 4 && EQL("line")) {
  135.             pp_line();
  136.             return;
  137.         }
  138.         goto not_pp;
  139.  
  140.     case 'p':
  141.         if (t_length == 6 && EQL("pragma")) {
  142.             /* Do NOTHING!! */
  143.             skip_pp();
  144.             return;
  145.         }
  146.         goto not_pp;
  147.     
  148.     case 'u':
  149.         if (t_length == 5 && EQL("undef")) {
  150.             pp_undef();
  151.             return;
  152.         }
  153.         goto not_pp;
  154.  
  155.     default:
  156.         goto not_pp;
  157.     }
  158.     
  159. not_alpha:
  160.     /*
  161.         Be more permissive than the new C standard.
  162.         Just skip the rest of the line.
  163.     */
  164.     skip_pp();
  165.     return;
  166.  
  167. not_pp:
  168.     err2(t_symbol, " is not a valid preprocessor directive.");
  169.     skip_pp();
  170. }
  171.  
  172. #undef EQL
  173.  
  174. /*
  175.     Handle the #error directive.
  176.     Produce a diagnostic message.
  177. */
  178. static char    err_msg[] = "#error:  ";
  179.  
  180. static void
  181. pp_error()
  182. {
  183.     char    message[MAX_SYMBOL];
  184.     int    i;
  185.  
  186.     strcpy(message, err_msg);
  187.     for (i = strlen(message); i < MAX_SYMBOL; i++) {
  188.         if (ch == '\n' || ch == END_FILE) {
  189.             break;
  190.         }
  191.         else {
  192.             message[i] = ch;
  193.             sysnext();
  194.         }
  195.     }
  196.     message[i] = '\0';
  197.     fatal(message);
  198. }
  199.         
  200.     
  201. /*
  202.     Evaluate a constant expression to either true or false.
  203.     A constant expression consists of:
  204.  
  205.     1. integer constants or character constants
  206.     2. the unary - + and ~ operators
  207.     3. the binary + - * / & | ^ << >> == != < > <= >= oprators
  208.     4. the ternary ? : operator
  209.     5. the ( and ) groupers.
  210.  
  211.     Identifiers are expanded if they are defined, otherwise they
  212.     are taken to have a value of zero. All arithmetic is integer and
  213.     ints are expanded to long.
  214. */
  215.  
  216. #define MAX_EVAL_VAL 100
  217. #define MAX_EVAL_OP 50
  218.  
  219. static    long         val_stack[MAX_EVAL_VAL];
  220. static    int        val_ptr = 0;
  221. static    en_tokens    op_stack[MAX_EVAL_OP];
  222. static    int        op_ptr = 0;
  223. static long result;
  224. static bool paren_seen;
  225. static bool error_seen;
  226.  
  227. static long
  228. eval()
  229. {
  230.     TRACETOK("eval");
  231.  
  232.     error_seen = FALSE;
  233.     get_token(TRUE);
  234.     result = eval1();
  235.  
  236.     RETURN_LONG("eval", result);
  237. }
  238.  
  239. static char    * junk;
  240. static int    junki;
  241.  
  242. static long
  243. eval1()
  244. {
  245.     register en_tokens op, op2;
  246.     register long val1, val2, val3;
  247.     int op_1ptr;
  248.  
  249.     TRACETOK("eval1");
  250.  
  251.     op_1ptr  = op_ptr;
  252.  
  253.     /* State S1: unary +, unary -, !, ~, constant or id is expected here. */
  254.  
  255. s1:
  256.     TRACEPN("v_eval1", printf("at state 1\n"));
  257.  
  258.     while (is(PLUS_TOK) || is(MINUS_TOK) || is(TILDE_TOK) || is(NOT_TOK)) {
  259.         if (is(PLUS_TOK)) {
  260.             push_op(UPLUS_TOK);
  261.         }
  262.         else if (is(MINUS_TOK)) {
  263.             push_op(UMINUS_TOK);
  264.         }
  265.         else if (is(NOT_TOK)) {
  266.             push_op(NOT_TOK);
  267.         }
  268.         else {
  269.             push_op(TILDE_TOK);
  270.         }
  271.         get_token(TRUE);
  272.     }
  273.  
  274.     /* We expect a constant or identifier here. */
  275.     if (is(INT_TOK) || is(LONG_TOK) || is(CHAR_TOK)) {
  276.         push_val((long) t_value);
  277.         get_token(TRUE);
  278.     }
  279.     else if (is(ID_TOK)) {
  280.         /* Special case defined id and defined(id). */
  281.         if (str_eq(t_symbol, "defined")) {
  282.  
  283.             /* Do not macro expand an id here! */
  284.             get_token(FALSE);
  285.             if (!is(ID_TOK) && !is(LPAREN_TOK)) {
  286.                 error("Id or '(' expected after 'defined'.");
  287.                 goto bad_expr;
  288.             }
  289.             paren_seen = is(LPAREN_TOK);
  290.             if (paren_seen) {
  291.                 get_token(FALSE);
  292.                 if (!is(ID_TOK)) {
  293.                     error("Id expected after '('.");
  294.                     goto bad_expr;
  295.                 }
  296.             }
  297.             if(mst_lookup(t_symbol, &junk, &junki)) {
  298.                 push_val(1L);
  299.             }
  300.             else {
  301.                 push_val(0L);
  302.             }
  303.             get_token(TRUE);
  304.             if (paren_seen) {
  305.                 if (is(RPAREN_TOK)) {
  306.                     get_token(TRUE);
  307.                 }
  308.                 else {
  309.                     error("')' expected.");
  310.                     goto bad_expr;
  311.                 }
  312.             }
  313.         }
  314.         else {
  315.             /* The identifier must be undefined, so it gets 0. */
  316.             push_val(0L);
  317.             get_token(TRUE);
  318.         }
  319.     }
  320.     else if (is(LPAREN_TOK)) {
  321.         get_token(TRUE);
  322.  
  323.         /* Evaluate the expression recursively. */        
  324.         result = eval1();
  325.         if (is(RPAREN_TOK)) {
  326.             get_token(TRUE);
  327.             push_val(result);
  328.         }
  329.         else {
  330.             error("')' expected.");
  331.             goto bad_expr;
  332.         }
  333.     }        
  334.     else {
  335.         error("Integer constant or parenthesized expression expected.");
  336.         goto bad_expr;
  337.     }
  338.  
  339.     /* Perform all unary ops and enter state S2. */
  340.     TRACEPN("v_eval1", printf("at state 1A\n"));
  341.     while (op_ptr > op_1ptr) {
  342.         switch (op = pop_op()) {
  343.         case UPLUS_TOK:     break;
  344.         case UMINUS_TOK: push_val(-pop_val());        break;
  345.         case NOT_TOK:     push_val((long)(!pop_val()));    break;
  346.         case TILDE_TOK:     push_val(~pop_val());        break;
  347.         default:     push_op(op);            goto s2;
  348.         }
  349.     }
  350.  
  351.     /* State S2: binary op or end_of_expression expected here. */
  352.  
  353. s2:
  354.     TRACEPN("v_eval1", printf("at state 2\n"));
  355.  
  356.     /*
  357.         Perform binary operators until the operator stack is
  358.         empty or until token operator has a higher precedence
  359.         than the operator on the top of the operator stack.
  360.     */
  361.  
  362.     while (op_ptr > op_1ptr && gt_prec(op_stack[op_ptr - 1], token)) {
  363.  
  364.         val2 = pop_val();
  365.         val1 = pop_val();
  366.         op   = pop_op();
  367.  
  368.         switch (op) {
  369.         case PLUS_TOK:        push_val(val1 + val2);    break;
  370.         case MINUS_TOK:        push_val(val1 - val2);    break;
  371.         case STAR_TOK:        push_val(val1 * val2);    break;
  372.         case DIV_TOK:        push_val((long)(val2?(val1/val2):0));
  373.                     break;
  374.         case MOD_TOK:        push_val(val1 % val2);    break;
  375.         case AND_TOK:        push_val(val1 & val2);    break;
  376.         case OR_TOK:        push_val(val1 | val2);    break;
  377.         case XOR_TOK:        push_val(val1 ^ val2);    break;
  378.         case LSHIFT_TOK:    push_val(val1 << val2);    break;
  379.         case RSHIFT_TOK:    push_val(val1 >> val2);    break;
  380.         case EQUAL_TOK:        push_val((long)(val1 == val2));    break;
  381.         case NE_TOK:        push_val((long)(val1 != val2));    break;
  382.         case LT_TOK:        push_val((long)(val1 <  val2));    break;
  383.         case GT_TOK:        push_val((long)(val1 >  val2));    break;
  384.         case LE_TOK:        push_val((long)(val1 <= val2));    break;
  385.         case GE_TOK:        push_val((long)(val1 >= val2));    break;
  386.         case LAND_TOK:        push_val((long)(val1 && val2)); break;
  387.         case LOR_TOK:        push_val((long)(val1 || val2)); break;
  388.  
  389.         case COLON_TOK:        op2 = pop_op()